#!/usr/bin/env python
# vim:fileencoding=utf-8
import json
import time
from urllib.parse import quote, urlencode

from calibre.ebooks.BeautifulSoup import BeautifulSoup
from calibre.web.feeds.news import BasicNewsRecipe


class WSJ(BasicNewsRecipe):
    title = 'The Wall Street Journal'
    __author__ = 'unkn0wn'
    description = (
        'The Print Edition of WSJ. The Wall Street Journal is your source '
        'for breaking news, analysis and insights from the U.S. and '
        "around the world, the world's leading business and finance publication."
    )
    language = 'en_US'
    masthead_url = 'https://s.wsj.net/media/wsj_amp_masthead_lg.png'
    encoding = 'utf-8'
    no_javascript = True
    no_stylesheets = True
    remove_attributes = ['style', 'height', 'width']
    resolve_internal_links = True

    recipe_specific_options = {
        'date': {
            'short': 'The date of the edition to download (YYYY-MM-DD format)\nOnly the past 6 editions will be available ',
            'long': 'For example, 2024-05-13',
        },
        'res': {
            'short': 'For hi-res images, select a resolution from the\nfollowing options: 800, 1000, 1200 or 1500',
            'long': 'This is useful for non e-ink devices, and for a lower file size\nthan the default, use 400 or 300.',
            'default': '600',
        },
    }

    extra_css = '''
        #big-top-caption { font-size:small; text-align:center; }
        [data-type:"tagline"] { font-style:italic; color:#202020; }
        .auth, time { font-size:small; }
        .sub, em, i { color: #202020; }
    '''

    keep_only_tags = [
        dict(name=['h1', 'h2']),
        dict(attrs={'aria-describedby': 'big-top-caption'}),
        dict(attrs={'id': 'big-top-caption'}),
        dict(name='article', attrs={'style': lambda x: x and 'article-body' in x}),
    ]

    remove_tags = [
        dict(attrs={'data-type': ['inset', 'video']}),
        dict(attrs={'data-testid': 'ad-container'}),
        dict(attrs={'data-spotim-app': 'conversation'}),
        dict(name=['button', 'svg', 'old-script', 'video']),
        dict(
            attrs={
                'aria-label': [
                    'Sponsored Offers',
                    'Listen To Article',
                    'What to Read Next',
                    'Utility Bar',
                    'Conversation',
                    'List of Comments',
                    'Comment',
                    'JR More Articles',
                ]
            }
        ),
        dict(
            attrs={
                'data-spot-im-class': [
                    'message-text',
                    'messages-list',
                    'message-view',
                    'conversation-root',
                ]
            }
        ),
        dict(
            attrs={
                'id': lambda x: x
                and x.startswith((
                    'comments_sector',
                    'wrapper-INLINE',
                    'audio-tag-inner-audio-',
                    'article-comments-tool',
                ))
            }
        ),
        dict(name='div', attrs={'data-message-depth': True}),
    ]

    articles_are_obfuscated = True

    def get_obfuscated_article(self, url):
        from calibre.scraper.simple import read_url
        raw = read_url([], 'https://archive.is/latest/' + url)
        return {'data': raw, 'url': url}

    def preprocess_html(self, soup):
        res = '?width=600'
        w = self.recipe_specific_options.get('res')
        if w and isinstance(w, str):
            res = '?width=' + w
        for img in soup.findAll('img', attrs={'currentsourceurl': True}):
            img['src'] = img['currentsourceurl'].split('?')[0] + res
        for p in soup.findAll('div', attrs={'data-type': ['paragraph', 'image']}):
            p.name = 'p'
        for a in soup.findAll('a', href=True):
            a['href'] = 'http' + a['href'].split('http')[-1]
        for figc in soup.findAll('figcaption'):
            figc['id'] = 'big-top-caption'
        if name := soup.find('h2', attrs={'itemprop': 'name'}):
            name.extract()
        for h2 in soup.findAll('h2'):
            if self.tag_to_string(h2).startswith(('What to Read Next', 'Conversation')):
                h2.extract()
            h2.name = 'h3'
            h2['class'] = 'sub'
        for ph in soup.findAll('a', attrs={'data-type': ['phrase', 'link']}):
            if div := ph.findParent('div'):
                div.name = 'span'
        for auth in soup.findAll(
            'a', attrs={'aria-label': lambda x: x and x.startswith('Author page')}
        ):
            if div := auth.find_previous_sibling('div'):
                div.name = 'span'
            if parent := auth.findParent('div'):
                parent['class'] = 'auth'
        for x in soup.findAll('ufc-follow-author-widget'):
            if y := x.findParent('div'):
                y.extract()
        return soup

    def _download_cover(self):
        import os
        from contextlib import closing

        from calibre import browser
        from calibre.utils.img import save_cover_data_to

        br = browser()
        dt = self.recipe_specific_options.get('date')
        if (dt and isinstance(dt, str)):
            d, m, y = dt.split('-')
            cu = f'https://www.wsj.com/public/resources/documents/WSJNewsPaper-{int(m)}-{int(d)}-{y}.jpg'
        else:
            raw = br.open('https://frontpages.freedomforum.org/newspapers/wsj-The_Wall_Street_Journal')
            soup = BeautifulSoup(raw.read())
            cu = soup.find(
                    'img',
                    attrs={
                        'alt': 'Front Page Image',
                        'src': lambda x: x and x.endswith('front-page-large.jpg'),
                    },
                )['src'].replace('-large', '-medium')
        self.report_progress(1, _('Downloading cover from %s') % cu)
        with closing(br.open(cu, timeout=self.timeout)) as r:
            cdata = r.read()
        cpath = os.path.join(self.output_dir, 'cover.jpg')
        save_cover_data_to(cdata, cpath)
        self.cover_path = cpath

    def get_browser(self, *args, **kw):
        br = BasicNewsRecipe.get_browser(self, *args, **kw)
        br.addheaders += [
            ('apollographql-client-name', 'wsj-mobile-android-release'),
        ]
        return br

    def parse_index(self):
        query = {
            'operationName': 'IssueQuery',
            'variables': '{"publication":"WSJ","region":"US","masthead":"ITPNEXTGEN"}',
            'extensions': '{"persistedQuery":{"version":1,"sha256Hash":"d938226e7d1c1fff050e7d084c72179e2713dcf4736d3a442c618c55b896f847"}}',
        }
        url = 'https://shared-data.dowjones.io/gateway/graphql?' + urlencode(
            query, safe='()!', quote_via=quote
        )
        raw = self.index_to_soup(url, raw=True)

        cat_data = json.loads(raw)['data']['mobileIssuesByMasthead']
        edit = [x['datedLabel'] for x in cat_data][1:]
        self.log('**Past Editions available : ' + ' | '.join(edit))

        past_edition = self.recipe_specific_options.get('date')

        for itm in cat_data:
            if past_edition and isinstance(past_edition, str):
                if past_edition in itm['publishedDateUtc']:
                    self.timefmt = ' [' + itm['datedLabel']
                    sections_ = itm['sections']
                    break
            self.timefmt = f' [{itm["datedLabel"]}]'
            sections_ = itm['sections']
            break

        self.log('Downloading ', self.timefmt)

        feeds = []

        for sec in sections_[:-1]:
            time.sleep(3)
            section = sec['label']
            self.log(section)
            cont_id = sec['key']

            query = {
                'operationName': 'SectionQuery',
                'variables': '{{"id":"{}"}}'.format(cont_id),
                'extensions': '{"persistedQuery":{"version":1,"sha256Hash":"207fe93376f379bf223ed2734cf9313a28291293366a803db923666fa6b45026"}}',
            }
            sec_url = 'https://shared-data.dowjones.io/gateway/graphql?' + urlencode(
                query, safe='()!', quote_via=quote
            )
            sec_raw = self.index_to_soup(sec_url, raw=True)

            sec_data = json.loads(sec_raw)['data']['summaryCollectionContent'][
                'collectionItems'
            ]

            articles = []

            for art in sec_data:
                for arts in art['collectionItems']:
                    mobi = arts['content']['mobileSummary']
                    title = mobi['headline']['text']
                    try:
                        desc = mobi['description']['content']['text']
                    except TypeError:
                        desc = ''
                    url = arts['content']['sourceUrl']
                    self.log('          ', title, '\n\t', desc, '\n\t', url)
                    articles.append({'title': title, 'description': desc, 'url': url})
            feeds.append((section, articles))
        return feeds
